public class NatoCaseStateTable 
{
    // Custom Exception class
    public class ArgumentException extends Exception {}
        
    // Roles
    //private static final string Role_OE = 'Order Entry';
    //private static final string Role_AP = 'Ad Production Rep';
    //private static final string Role_SS = 'Sales//Customer Support';
    private static final string Role_OV = 'Order Validation';
    private static final string Role_QC = 'IOG OOR - AP - Rep';
    private static final string Role_QC2 = 'IOG OOR - QC - Rep';
    private static final string Role_Billing = 'Billing';
    
    // Queues
    public static final string Queue_OV = 'National Order Validation';
    public static final string Queue_OE = 'National Order Entry';
    public static final string Queue_AP = 'National Ad Production';
    public static final string Queue_QC = 'National Quality Control';
    public static final string Queue_Billing = 'National Billing';
    
    
    // States
    public static final string AP_Edit_to_OE = 'AP Edit to OE';
    public static final string AP_Edit_to_OV = 'AP Edit to OV';
    public static final string AP_Query_to_SS = 'AP Query to SS';
    public static final string AP_Release_Live = 'AP Release Live';
    public static final string AP_Response_to_QC = 'AP Response to QC';
    public static final string AP_in_Progress = 'AP in Progress';
    public static final string Billing_Complete = 'Billing Complete';
    public static final string Billing_Query_to_SS = 'Billing Query to SS';
    public static final string Billing_in_Progress = 'Billing in Progress';
    public static final string Future_Start_Date = 'Future Start Date';
    public static final string OC_Edit_to_OE = 'OC Edit to OE';
    public static final string OE_Edit_to_OV = 'OE Edit to OV';
    public static final string OE_Query_to_SS = 'OE Query to SS';
    public static final string OE_Release_Live = 'OE Release Live';
    public static final string OE_Response_to_AP = 'OE Response to AP';
    public static final string OE_Response_to_QC = 'OE Response to QC';
    public static final string OE_With_Vendor = 'OE With Vendor';
    public static final string OE_in_Progress = 'OE in Progress';
    public static final string OV_Pre_Fulfillment_to_SS = 'OV Pre-Fulfillment to SS';
    public static final string OV_Query_to_SS = 'OV Query to SS';
    public static final string OV_Response_to_AP = 'OV Response to AP';
    public static final string OV_Response_to_OE = 'OV Response to OE';
    public static final string OV_Response_to_QC = 'OV Response to QC';
    public static final string OV_in_Progress = 'OV in Progress';
    public static final string QC_Edit_to_AP = 'QC Edit to AP';
    public static final string QC_Edit_to_OE = 'QC Edit to OE';
    public static final string QC_Edit_to_OV = 'QC Edit to OV';
    public static final string QC_Fulfilled = 'QC Fulfilled';
    public static final string QC_Query_to_SS = 'QC Query to SS';
    public static final string QC_Release_Live = 'QC Release Live';
    public static final string QC_in_Progress = 'QC in Progress';
    public static final string Query_to_Client = 'Query to Client';
    public static final string Ready_for_2nd_QC = 'Ready for 2nd QC';
    public static final string Ready_for_AP = 'Ready for AP';
    public static final string Ready_for_Billing = 'Ready for Billing';
    public static final string Ready_for_OE = 'Ready for OE';
    public static final string Ready_for_OV = 'Ready for OV';
    public static final string Ready_for_QC = 'Ready for QC';
    public static final string Released_Live = 'Released Live';
    public static final string SS_Fulfilled = 'SS Fulfilled';
    public static final string SS_Response_to_AP = 'SS Response to AP';
    public static final string SS_Response_to_Billing = 'SS Response to Billing';
    public static final string SS_Response_to_OE = 'SS Response to OE';
    public static final string SS_Response_to_OV = 'SS Response to OV';
    public static final string SS_Response_to_QC = 'SS Response to QC';
    public static final string SS_With_Vendor = 'SS With Vendor';
    public static final string Site_Issue = 'Site Issue';
    public static final string Cancelled = 'Cancelled';

    // Private members
    
    // Map Queues Names to their IDs
    private static Map<string, ID> queueMap = null;
    
    // Map Role IDs to their Role Names
    private static Map<ID, UserRole> userRoleMap = null;
    
    // Returns true if the state is a Billing state (i.e. only for Insertion Orders)
    public static boolean IsBillingState(string state){
        return (state == Ready_for_Billing) ||
               (state == Billing_in_Progress) ||
               (state == Billing_Complete) ||
               (state == SS_Response_to_Billing);           
    }
          
    // Set Rep On Assignment Chage - Populates the Case's NATO 'Case Team' section on the page layout
    // (not to be confused with the Case Team) when the assignment of the case changes
    // Parameters: 
    //      oldCase - the 'before' image of the case object
    //      newCse - the current (new) case object
    public static void SetRepOnAssignmentChage(Case oldCase, Case newCase){
        
        System.assert(oldCase.OwnerId != newCase.OwnerId);
        
        // If the case is moving from the OE Queue to a rep we store the rep
        if(newCase.Status == Ready_for_OE && 
        newCase.Order_Entry__c == null && newCase.OwnerId != GetCaseQueueID(Queue_OE)){
            newCase.Order_Entry__c = newCase.OwnerId;
        }
        else if(newCase.Status == Ready_for_AP && 
        newCase.Ad_Production__c == null && newCase.OwnerId != GetCaseQueueID(Queue_AP)){
            newCase.Ad_Production__c = newCase.OwnerId;
        }       
    }
    
    /*
    public static boolean IsResponse(string state){
        return (state != null) && state.contains('Response');
    }*/

    //  Set Owner On State Chage - Sets the case owner when the case state changes
    // Parameters: 
    //      newState - the new state of the case
    //      caseObject - the case Object
    // Note: This should be called for both insertions and updates
    public static void SetOwnerOnStateChage(string newState, Case caseObject){
            
        if(newState == Ready_for_OV){
            caseObject.OwnerId = GetCaseQueueID(Queue_OV);
        }else if(newState == OV_in_Progress){
            caseObject.OwnerId = UserInfo.getUserId();
            //VerifyRoleName(Role_OV, caseObject);
            caseObject.NATO_Rep_OV__c = caseObject.OwnerId;
        }else if((newState == OE_Edit_to_OV) ||
            (newState == AP_Edit_to_OV) ||
            (newState == QC_Edit_to_OV) ||
            (newState == SS_Response_to_OV)){
            // Assign to OV Rep
            if(caseObject.NATO_Rep_OV__c == null)
                caseObject.OwnerId.addError('An Order Validation Rep has not been linked to this case.');
            else
                caseObject.OwnerId = caseObject.NATO_Rep_OV__c;
            
        // Order Entry States
        }else if(newState == Ready_for_OE){
            if(caseObject.Order_Entry__c == null)
                caseObject.OwnerId = GetCaseQueueID(Queue_OE);
            else
                caseObject.OwnerId = caseObject.Order_Entry__c;
        }else if(newState == OE_in_Progress ){ //sree               
                caseObject.OwnerId          = UserInfo.getUserId();
                caseObject.Order_Entry__c   = UserInfo.getUserId();             
        }else if((newState == SS_Response_to_OE) ||
        (newState == OV_Response_to_OE) ||
        (newState == AP_Edit_to_OE) ||
        (newState == QC_Edit_to_OE)){
            // Assign to OE Rep
            if(caseObject.Order_Entry__c == null)
                caseObject.OwnerId.addError('An Order Entry Rep has not been linked to this case.');
            else
                caseObject.OwnerId = caseObject.Order_Entry__c;

        // Ad Production States
        }else if(newState == Ready_for_AP){
            if(caseObject.Ad_Production__c == null)
                caseObject.OwnerId = GetCaseQueueID(Queue_AP);
            else
                caseObject.OwnerId = caseObject.Ad_Production__c;
        }else if(newState == AP_in_Progress ){ //sree               
                caseObject.OwnerId          = UserInfo.getUserId();
                caseObject.Ad_Production__c = UserInfo.getUserId();                             
        }else if((newState == SS_Response_to_AP) ||
        (newState == OV_Response_to_AP) ||
        (newState == OE_Response_to_AP) ||
        (newState == QC_Edit_to_AP)) {
            // Assign to AP Rep
            if(caseObject.Ad_Production__c == null)
                caseObject.OwnerId.addError('An Ad Production Rep has not been linked to this case.');
            else
                caseObject.OwnerId = caseObject.Ad_Production__c;


        // Quality Control States
        }else if(newState == Ready_for_QC){
            if(caseObject.Quality_Control__c == null){
                caseObject.OwnerId = GetCaseQueueID(Queue_QC);
                caseObject.NATO_QC_Level__c = 1;
            }else{
                caseObject.OwnerId = caseObject.Quality_Control__c;
            }           
        }else if(newState == QC_in_Progress){
            caseObject.OwnerId = UserInfo.getUserId();
            //VerifyRoleName(new Set<string>{Role_QC, Role_QC2}, caseObject);
            if(caseObject.NATO_QC_Level__c == null)
                caseObject.NATO_QC_Level__c = 1;
                
            if(caseObject.NATO_QC_Level__c == 1)
                caseObject.Quality_Control__c = caseObject.OwnerId; 
            else if(caseObject.NATO_QC_Level__c == 2)
                caseObject.Nato_Rep_QC2__c = caseObject.OwnerId; 
            else
                caseObject.NATO_QC_Level__c.addError('The QC Level of the case is not supported. Level:' + caseObject.NATO_QC_Level__c);
        }else if((newState == SS_Response_to_QC) ||
        (newState == OV_Response_to_QC) ||
        (newState == OE_Response_to_QC) ||
        (newState == AP_Response_to_QC)){
            // Assign to QC Rep
            if(caseObject.NATO_QC_Level__c == null)
                    caseObject.NATO_QC_Level__c = 1;

            if(caseObject.NATO_QC_Level__c == 1){
                if(caseObject.Quality_Control__c == null)
                    caseObject.OwnerId.addError('A Quality Control (Level 1) Rep has not been linked to this case.');
                else
                    caseObject.OwnerId = caseObject.Quality_Control__c;
            }else if(caseObject.NATO_QC_Level__c == 2){
                if(caseObject.Nato_Rep_QC2__c == null)
                    caseObject.OwnerId.addError('A Quality Control (Level 2) Rep has not been linked to this case.');
                else
                    caseObject.OwnerId = caseObject.Nato_Rep_QC2__c;
            }else
                caseObject.NATO_QC_Level__c.addError('The QC Level of the case is not supported. Level:' + caseObject.NATO_QC_Level__c);
            
        }else if(newState == Ready_for_2nd_QC){
            if(caseObject.Nato_Rep_QC2__c == null){
                caseObject.OwnerId = GetCaseQueueID(Queue_QC);
                caseObject.NATO_QC_Level__c = 2;
            }else{
                caseObject.OwnerId = caseObject.Nato_Rep_QC2__c;
            }

        // Sales Support States
        }else if((newState == OV_Pre_Fulfillment_to_SS) ||
        (newState == OV_Query_to_SS) ||
        (newState == OE_Query_to_SS) ||
        (newState == AP_Query_to_SS) ||
        (newState == QC_Query_to_SS) ||
        (newState == QC_Fulfilled) ||
        (newState == Billing_Query_to_SS) ||
        (newState == Billing_Complete)){
            // Assign to SS Rep
            if(caseObject.Nato_Rep_SS__c == null)
                caseObject.OwnerId.addError('A Sales Support Rep has not been linked to this case.');
            else
                caseObject.OwnerId = caseObject.Nato_Rep_SS__c;

        // Billing States
        }else if(newState == Ready_for_Billing){
            caseObject.OwnerId = GetCaseQueueID(Queue_Billing);
        }else if(newState == Billing_in_Progress){
            caseObject.OwnerId = UserInfo.getUserId();
            //VerifyRoleName(Role_Billing, caseObject);
            caseObject.Billing__c = caseObject.OwnerId; 
        }else if(newState == SS_Response_to_Billing){
            // Assign to AP Rep
            if(caseObject.Billing__c == null)
                caseObject.OwnerId.addError('A Billing Rep has not been linked to this case.');
            else
                caseObject.OwnerId = caseObject.Billing__c;         
        }
    }
    
    // Set Counter On State Chage - Updates the case counters when the case state changes
    // Parameters:
    //      newState - the new state of the case
    //      newCaseObject - the case object
    //      oldCaseObject - the 'before' image of the case object (may be null for insertions)
    // Note: This should be called for both insertions and updates
    public static void SetCounterOnStateChage(string newState, Case newCaseObject, Case oldCaseObject){
        if(oldCaseObject == null)
            oldCaseObject = new Case();
        
        if(newState == Billing_Query_to_SS)
            newCaseObject.Billing_Query_Counter__c = IncrementCounter(oldCaseObject.Billing_Query_Counter__c);      
                    
        if((newState == OE_Edit_to_OV) ||
        (newState == AP_Edit_to_OV) ||
        (newState == QC_Edit_to_OV) ||
        (newState == AP_Edit_to_OE) ||
        (newState == QC_Edit_to_OE) ||
        (newState == QC_Edit_to_AP))
        {
            newCaseObject.Edit_Counter__c = IncrementCounter(oldCaseObject.Edit_Counter__c);
        }
        

        if((newState == OV_Query_to_SS) ||
        (newState == OE_Query_to_SS) ||
        (newState == AP_Query_to_SS) ||
        (newState == QC_Query_to_SS))
        {
            newCaseObject.Query_Counter__c = IncrementCounter(oldCaseObject.Query_Counter__c);
        }
    }

    //  IncrementCounter - helpr to increment a counter
    private static Decimal IncrementCounter(Decimal counter){
        if(counter == null || counter <= 0)
            return 1;
        else
            return counter+1;
    }
    
    //  Validate State Requirements - verify that the requirements have been met to move to a new state
    //  Parameters:
    //      newState - the new state of the case
    //      caseObject - the case object to verify
    //  Returns: A list of errors (or an empty list on success)
    public static List<string> ValidateStateRequirements(string newState, Case caseObject){
        List<string> errors = new List<string>();
        
        if((newState == Ready_for_OE) || 
        (newState == Future_Start_Date)){
            if(caseObject.Nato_Rep_SS__c == null)
                errors.add('The case team must have a Sales Support rep.');                     
        }
        if(newState == Future_Start_Date){
            if(caseObject.Future_Start_Date__c == null)
                errors.add('The case must have a Future Start Date in order to move to this status.');
            else if(caseObject.Future_Start_Date__c <= Date.today())
                errors.add('The case must have a Future Start Date that occurs in the future in order to move to this status.');                
        }
        
        return errors;
    }
    
    // Get Possible States - Returns a list of possible states given the current state
    // Parameters:
    //      currentState - the current state of the case
    //      isReleasedToLiveChecked - is the case released to live?
    //      addBillingStates - can this case move to billing states (yes for Insertion Orders, no for Change Requests)
    //      futureStartDate - does the case have a future start date?
    //      qcLevel - the QC level fo the case
    //      ssRel = the SS Rep of the case
    //      oeRel = the OE Rep of the case
    //      apRel = the AP Rep of the case
    //      qcRel = the QC Rep of the case
    //      qc2Rel = the Second QC Rep of the case
    // Notes: To be used for Insertion Order and Change Request record types only.
    public static Set<string> GetPossibleStates(string currentState, boolean isReleasedToLiveChecked, 
    boolean addBillingStates, date futureStartDate, decimal qcLevel,
    ID ssRep, ID oeREp, ID apRep, ID qcRep, ID qc2Rep, ID billingRep)
    {
        Set<string> states = new Set<string>();
        
        //states.add(Cancelled); // You can always cancel
        
        if(currentState == null){
            states.add(Ready_for_OV);
            
        // Order Validation States
        }else if(currentState == Future_Start_Date){
            if(futureStartDate <= Date.today())
                states.add(Ready_for_OE);
        }else if(currentState == Ready_for_OV){
            states.add(OV_in_Progress);
        }else if(currentState == OV_in_Progress){
            if(futureStartDate == null || futureStartDate <= Date.today()){
                states.add(Ready_for_OE);
                if(!addBillingStates)
                    states.add(Ready_for_AP);                       
            }
            states.add(OV_Pre_Fulfillment_to_SS);
            states.add(Future_Start_Date);
            states.add(OV_Query_to_SS);
        }else if(currentState == OE_Edit_to_OV){
            states.add(OV_Response_to_OE);
            states.add(OV_Query_to_SS);
        }else if(currentState == AP_Edit_to_OV){
            states.add(OV_Response_to_AP);
            states.add(OV_Query_to_SS);
        }else if(currentState == QC_Edit_to_OV){
            states.add(OV_Response_to_QC);
            states.add(OV_Query_to_SS);
        }else if(currentState == SS_Response_to_OV){
            if(OERep == null)
                states.add(Ready_for_OE);
            if(OERep != null)
                states.add(OV_Response_to_OE);
            if(APRep == null && !addBillingStates)
                states.add(Ready_for_AP);
            if(APRep != null)
                states.add(OV_Response_to_AP);
            if(QCRep != null)
                states.add(OV_Response_to_QC);
            states.add(OV_Query_to_SS);
            states.add(Future_Start_Date);

        // Order Entry States
        }else if(currentState == Ready_for_OE){
            states.add(OE_in_Progress);
        }else if(currentState == OE_in_Progress){
            states.add(OE_With_Vendor);
            if(!isReleasedToLiveChecked)
                states.add(OE_Release_Live);
            states.add(Ready_for_AP);
            states.add(Ready_for_QC);
            states.add(OE_Edit_to_OV);
            states.add(OE_Query_to_SS);
        }else if(currentState == OE_With_Vendor){
            if(!isReleasedToLiveChecked)
                states.add(OE_Release_Live);
            if(APRep == null)
                states.add(Ready_for_AP);
            if(QCRep == null)
                states.add(Ready_for_QC);
            states.add(OE_Edit_to_OV);
            states.add(OE_Query_to_SS);
        }else if(currentState == SS_Response_to_OE){
            states.add(OE_With_Vendor);
            if(!isReleasedToLiveChecked)
                states.add(OE_Release_Live);
            if(APRep == null)
                states.add(Ready_for_AP);
            if(QCRep == null)
                states.add(Ready_for_QC);
            states.add(OE_Edit_to_OV);
            states.add(OE_Query_to_SS);
            if(APRep != null)
                states.add(OE_Response_to_AP);
            if(QCRep != null)
                states.add(OE_Response_to_QC);
        }else if(currentState == OV_Response_to_OE){
            states.add(OE_With_Vendor);
            if(!isReleasedToLiveChecked)
                states.add(OE_Release_Live);
            if(APRep == null)
                states.add(Ready_for_AP);
            if(QCRep == null)
                states.add(Ready_for_QC);
            states.add(OE_Edit_to_OV);
            states.add(OE_Query_to_SS);
            if(APRep != null)
                states.add(OE_Response_to_AP);
            if(QCRep != null)
                states.add(OE_Response_to_QC);
        }else if(currentState == QC_Edit_to_OE){
            states.add(OE_Response_to_QC);
            states.add(OE_Edit_to_OV);
            states.add(OE_Query_to_SS);
        }else if(currentState == AP_Edit_to_OE){
            states.add(OE_Response_to_AP);
            states.add(OE_Edit_to_OV);
            states.add(OE_Query_to_SS);
        }else if(currentState == OE_Release_Live){
                states.add(Ready_for_QC);

        // Ad Production States
        }else if(currentState == Ready_for_AP){
            states.add(AP_in_Progress);
        }else if(currentState == AP_in_Progress){
            states.add(Ready_for_QC);
            if(!isReleasedToLiveChecked)
                states.add(AP_Release_Live);
            states.add(AP_Edit_to_OV);
            states.add(AP_Edit_to_OE);
            states.add(AP_Query_to_SS);
        }else if(currentState == SS_Response_to_AP){
            if(QCRep == null)
                states.add(Ready_for_QC);
            if(!isReleasedToLiveChecked)
                states.add(AP_Release_Live);
            states.add(AP_Edit_to_OV);
            states.add(AP_Edit_to_OE);
            states.add(AP_Query_to_SS);
            if(QCRep != null)
                states.add(AP_Response_to_QC);
        }else if(currentState == OV_Response_to_AP){
            if(QCRep == null)
                states.add(Ready_for_QC);
            if(!isReleasedToLiveChecked)
                states.add(AP_Release_Live);
            states.add(AP_Edit_to_OV);
            states.add(AP_Edit_to_OE);
            states.add(AP_Query_to_SS);
            if(QCRep != null)
                states.add(AP_Response_to_QC);
        }else if(currentState == OE_Response_to_AP){
            if(QCRep == null)
                states.add(Ready_for_QC);
            if(!isReleasedToLiveChecked)
                states.add(AP_Release_Live);
            states.add(AP_Edit_to_OV);
            states.add(AP_Edit_to_OE);
            states.add(AP_Query_to_SS);
            if(QCRep != null)
                states.add(AP_Response_to_QC);
        }else if(currentState == QC_Edit_to_AP){
            states.add(AP_Response_to_QC);
            states.add(AP_Edit_to_OV);
            states.add(AP_Edit_to_OE);
            states.add(AP_Query_to_SS);
        }else if(currentState == AP_Release_Live){
                states.add(Ready_for_QC);


        // Quality Control States
        }else if(currentState == Ready_for_QC){
            states.add(QC_in_Progress);
        }else if(currentState == QC_in_Progress){
            if(!isReleasedToLiveChecked)
                states.add(QC_Release_Live);
            if(isReleasedToLiveChecked){
                if(addBillingStates)
                    states.add(Ready_for_Billing);      
            }
            states.add(QC_Fulfilled);           
            states.add(QC_Edit_to_OV);
            states.add(QC_Edit_to_OE);
            states.add(QC_Edit_to_AP);
            states.add(QC_Query_to_SS);
            states.add(Site_Issue);
            if(isReleasedToLiveChecked){
                if(qcLevel == 1 && QC2Rep == null)
                    states.add(Ready_for_2nd_QC);
            }
        }else if(currentState == SS_Response_to_QC){
            if(!isReleasedToLiveChecked)
                states.add(QC_Release_Live);
            if(isReleasedToLiveChecked){
                if(addBillingStates)
                    states.add(Ready_for_Billing);

            }
            states.add(QC_Fulfilled);           
            states.add(QC_Edit_to_OV);
            states.add(QC_Edit_to_OE);
            states.add(QC_Edit_to_AP);
            states.add(QC_Query_to_SS);
            states.add(Site_Issue);
            if(isReleasedToLiveChecked){
                if(qcLevel == 1 && QC2Rep == null)
                    states.add(Ready_for_2nd_QC);
            }
        }else if(currentState == OV_Response_to_QC){
            if(!isReleasedToLiveChecked)
                states.add(QC_Release_Live);
            if(isReleasedToLiveChecked){
                if(addBillingStates)
                    states.add(Ready_for_Billing);
            }
            states.add(QC_Fulfilled);           
            states.add(QC_Edit_to_OV);
            states.add(QC_Edit_to_OE);
            states.add(QC_Edit_to_AP);
            states.add(QC_Query_to_SS);
            states.add(Site_Issue);
            if(isReleasedToLiveChecked){
                if(qcLevel == 1 && QC2Rep == null)
                    states.add(Ready_for_2nd_QC);
            }
        }else if(currentState == OE_Response_to_QC){
            if(!isReleasedToLiveChecked)
                states.add(QC_Release_Live);
            if(isReleasedToLiveChecked){
                if(addBillingStates)
                    states.add(Ready_for_Billing);
            }
            states.add(QC_Fulfilled);           
            states.add(QC_Edit_to_OV);
            states.add(QC_Edit_to_OE);
            states.add(QC_Edit_to_AP);
            states.add(QC_Query_to_SS);
            states.add(Site_Issue);
            if(isReleasedToLiveChecked){
                if(qcLevel == 1 && QC2Rep == null)
                    states.add(Ready_for_2nd_QC);
            }
        }else if(currentState == AP_Response_to_QC){
            if(!isReleasedToLiveChecked)
                states.add(QC_Release_Live);
            if(isReleasedToLiveChecked){
                if(addBillingStates)
                    states.add(Ready_for_Billing);
            }
            states.add(QC_Fulfilled);           
            states.add(QC_Edit_to_OV);
            states.add(QC_Edit_to_OE);
            states.add(QC_Edit_to_AP);
            states.add(QC_Query_to_SS);
            states.add(Site_Issue);
            if(isReleasedToLiveChecked){
                if(qcLevel == 1 && QC2Rep == null)
                    states.add(Ready_for_2nd_QC);
            }
        }else if(currentState == Ready_for_2nd_QC){
            states.add(QC_in_Progress);
        }else if(currentState == Site_Issue){
            if(!isReleasedToLiveChecked)
                states.add(QC_Release_Live);
            if(isReleasedToLiveChecked){
                if(addBillingStates)
                    states.add(Ready_for_Billing);
            }
            states.add(QC_Fulfilled);           
            states.add(QC_Edit_to_OV);
            states.add(QC_Edit_to_OE);
            states.add(QC_Edit_to_AP);
            states.add(QC_Query_to_SS);
            if(isReleasedToLiveChecked){
                if(qcLevel == 1 && QC2Rep == null)
                    states.add(Ready_for_2nd_QC);
            }
        }else if(currentState == QC_Release_Live){
            if(isReleasedToLiveChecked){
                if(addBillingStates)
                    states.add(Ready_for_Billing);
            }
            states.add(QC_Fulfilled);           
            states.add(QC_Edit_to_OV);
            states.add(QC_Edit_to_OE);
            states.add(QC_Edit_to_AP);
            states.add(QC_Query_to_SS);
            states.add(Site_Issue);
            if(isReleasedToLiveChecked){
                if(qcLevel == 1 && QC2Rep == null)
                    states.add(Ready_for_2nd_QC);
            }

        // Sales Support States
        }else if(currentState == OV_Pre_Fulfillment_to_SS){
            states.add(Query_to_Client);
            states.add(Ready_for_OE);
            states.add(SS_With_Vendor);
            states.add(Future_Start_Date);
            states.add(Cancelled);          
        }else if(currentState == OV_Query_to_SS){
            states.add(Query_to_Client);
            states.add(SS_Response_to_OV);
            states.add(Cancelled);
        }else if(currentState == OE_Query_to_SS){
            states.add(Query_to_Client);
            states.add(SS_Response_to_OE);
            states.add(SS_With_Vendor);
            states.add(Cancelled);
        }else if(currentState == AP_Query_to_SS){
            states.add(Query_to_Client);
            states.add(SS_Response_to_AP);
            states.add(Cancelled);
        }else if(currentState == QC_Query_to_SS){
            states.add(Query_to_Client);
            states.add(SS_Response_to_QC);
            states.add(Cancelled);
        }else if(currentState == Query_to_Client){
            states.add(SS_Response_to_OV);
            if(OERep != null)
                states.add(SS_Response_to_OE);
            states.add(SS_Response_to_AP);
            states.add(SS_Response_to_QC);
            //if(addBillingStates && billingRep != null)
            //    states.add(SS_Response_to_Billing);  //sree
            //states.add(OV_Pre_Fulfillment_to_SS);  //sree         
            if(OERep == null)
                states.add(Ready_for_OE);
            states.add(Future_Start_Date);
            states.add(SS_With_Vendor);
            states.add(Cancelled);
        }else if(currentState == SS_With_Vendor){
            states.add(Query_to_Client);
            if(OERep == null)
                states.add(Ready_for_OE);
            states.add(Future_Start_Date);
            states.add(Cancelled);    
        }else if(currentState == Billing_Query_to_SS){
            states.add(Query_to_Client);
            states.add(SS_Response_to_Billing);
            states.add(Cancelled);
        }else if(currentState == Billing_Complete){
            states.add(SS_Fulfilled);
        }else if(currentState == QC_Fulfilled){
            states.add(SS_Fulfilled);
        }else if(currentState == SS_Fulfilled){

        // Billing States
        }else if(currentState == Ready_for_Billing){
            states.add(Billing_in_Progress);
        }else if(currentState == Billing_in_Progress){
            states.add(Billing_Complete);
            states.add(Billing_Query_to_SS);
        }else if(currentState == SS_Response_to_Billing){
            states.add(Billing_Complete);
            states.add(Billing_Query_to_SS);
            
        // Other States
        }else if(currentState == Cancelled){
            states.clear(); // Remove Cancelled
            states.add(AP_Edit_to_OE);
            states.add(AP_Edit_to_OV);
            states.add(AP_Query_to_SS);
            states.add(AP_Release_Live);
            states.add(AP_Response_to_QC);
            states.add(AP_in_Progress);
            states.add(Billing_Complete);
            states.add(Billing_Query_to_SS);
            if(addBillingStates)
                states.add(Billing_in_Progress);
            states.add(Future_Start_Date);
            states.add(OC_Edit_to_OE);
            states.add(OE_Edit_to_OV);
            states.add(OE_Query_to_SS);
            states.add(OE_Release_Live);
            states.add(OE_Response_to_AP);
            states.add(OE_Response_to_QC);
            states.add(OE_With_Vendor);
            states.add(OE_in_Progress);
            states.add(OV_Pre_Fulfillment_to_SS);
            states.add(OV_Query_to_SS);
            states.add(OV_Response_to_AP);
            states.add(OV_Response_to_OE);
            states.add(OV_Response_to_QC);
            states.add(OV_in_Progress);
            states.add(QC_Edit_to_AP);
            states.add(QC_Edit_to_OE);
            states.add(QC_Edit_to_OV);
            states.add(QC_Fulfilled);
            states.add(QC_Query_to_SS);
            states.add(QC_Release_Live);
            states.add(QC_in_Progress);
            states.add(Query_to_Client);
            states.add(Ready_for_2nd_QC);
            states.add(Ready_for_AP);
            if(addBillingStates)
                states.add(Ready_for_Billing);
            states.add(Ready_for_OE);
            states.add(Ready_for_OV);
            states.add(Ready_for_QC);
            states.add(Released_Live);
            states.add(SS_Fulfilled);
            states.add(SS_Response_to_AP);
            if(addBillingStates)
                states.add(SS_Response_to_Billing);
            states.add(SS_Response_to_OE);
            states.add(SS_Response_to_OV);
            states.add(SS_Response_to_QC);
            states.add(SS_With_Vendor);
            states.add(Site_Issue);
        }
        return states;
    }
    
    // Private Methods
    
    // GetCaseQueueID - Gets the ID of a Queue given the queue's name
    private static ID GetCaseQueueID(string queueName)
    {
        if(queueMap == null){
            queueMap = new Map<string, ID>();
            
            List<string> natoQueueNames = new List<string>{Queue_AP, Queue_Billing, Queue_OE, Queue_OV, Queue_QC};
            List<Group> queues = [Select Name, ID from Group where Type = 'Queue' and Name in :natoQueueNames];
            for(Group q: queues)
                queueMap.put(q.Name, q.ID);
        }
        
        ID queueId = queueMap.get(queueName);
        System.assert(queueId != null);
        return queueId;
    }
    
    /*
    // VerifyRoleName - verify that the current user belongs to a role
    // Parameters:
    //      roleName - the name of the role the user must belong to
    //      caseObject - used to set an error message on failure
    private static void VerifyRoleName(string roleName, Case caseObject){
        VerifyRoleName(new Set<string>{roleName}, caseObject);
    }
    
    // VerifyRoleName - verify that the current user belongs to a role
    // Parameters:
    //      roleNames - the list of acceptable role names
    //      caseObject - used to set an error message on failure
    private static void VerifyRoleName(Set<string> roleNames, Case caseObject){
        if(null == userRoleMap){

            List<string> rolesToLoad = new List<string>{Role_OV, Role_QC, Role_QC2, Role_Billing};          
            userRoleMap = new Map<Id, UserRole>([Select ID, Name from UserRole where Name in :rolesToLoad]);            
        }
        
        UserRole role = userRoleMap.get(UserInfo.getUserRoleId());
                
        if(role==null || !roleNames.contains(role.Name)){
            string roleNameMessage = null;
            for(string r : roleNames){
                if(roleNameMessage != null)
                    roleNameMessage += ' or ' + r;
                else
                    roleNameMessage = r;
            }
            caseObject.Status.addError('Only a user in the  "' + roleNameMessage + '" role can move case to this state.');
        }
    }
    */
}